package ru.amse.tsyganov.jumleditor.view;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;

import ru.amse.tsyganov.jumleditor.model.State;
import ru.amse.tsyganov.jumleditor.model.Transition;

public final class TransitionDraughtsman {

	public static void drawArrowedLine(GC gc, Line line, boolean arrowAtStart) {
		assert gc != null;
		
		gc.setBackground(Colors.getBlackColor());
		final int LIMIT_LINE_LENGTH = 4; 
		if (line.getLength() < LIMIT_LINE_LENGTH) {
			return;
		}
		int sourceX = arrowAtStart ? line.getX1() : line.getX2();
		int sourceY = arrowAtStart ? line.getY1() : line.getY2();
		
		int targetX = arrowAtStart ? line.getX2() : line.getX1();
		int targetY = arrowAtStart ? line.getY2() : line.getY1();


		double a = Math.atan2(targetY - sourceY, 
				sourceX - targetX);
		
		double a1 = a + Math.PI / 15;
		double a2 = a - Math.PI / 15;
		double len = 14;
		
		gc.setAntialias(SWT.ON);
		gc.drawLine(line.getX1(), line.getY1(),
				line.getX2(), line.getY2());

		gc.fillPolygon(new int[] {
				targetX, targetY, 
				(int) (targetX + len * Math.cos(a1)), 
				(int) (targetY - len * Math.sin(a1)),
				(int) (targetX + len * Math.cos(a2)), 
				(int) (targetY - len * Math.sin(a2))});
	}
	
	public static void drawTransition(GC gc, 
			TransitionView<? extends Transition> t) {
		
		if (gc == null || t == null) {
			throw new IllegalArgumentException();
		}
		
		StateView<? extends State> target = 
			t.getActivityGraphView().getModelViewMap().getStatesMap().get(
					t.getModel().getTarget().getContainer());
		
		StateView<? extends State> source = 
			t.getActivityGraphView().getModelViewMap().getStatesMap().get(
					t.getModel().getSource().getContainer());
		
		Point connectionPoint1 = target.getConnectionPoint(t.getStartPoint(), true);
		
		Point connectionPoint2 = source.getConnectionPoint(t.getEndPoint(), false);
		
		Line line = new Line(connectionPoint1.x, connectionPoint1.y, 
				connectionPoint2.x, connectionPoint2.y);
		
		drawArrowedLine(gc, line, false);
	}
	
	public static Point getConnectionPoint(
			Point sourcePoint, 
			Rectangle targetRect) { 
		
		double targetCX = targetRect.x + targetRect.width / 2.;
		double targetCY = targetRect.y + targetRect.height / 2.;
		
		int tx;
		int ty;
		
		if (((double) Math.abs(sourcePoint.x - targetCX) / 
				(double) Math.abs(sourcePoint.y - targetCY)) > 
					((double) targetRect.width / (double) targetRect.height)) {
			
			double dy = ((double) targetRect.width / 2) * 
				((double) (targetCY - sourcePoint.y) / 
						(double) (sourcePoint.x - targetCX));
			
			if (sourcePoint.x > targetCX) {
				tx = (int) (targetRect.x + targetRect.width);
				ty = (int) (targetCY - dy);
			} else {
				tx = (int) targetRect.x;
				ty = (int) (targetCY + dy);
			}
		} else {
			
			double dx = ((double) targetRect.height / 2) * 
				((double)(sourcePoint.x - targetCX) / 
						(double) (targetCY - sourcePoint.y));
			
			if (sourcePoint.y > targetCY) {
				tx = (int) (targetCX - dx);
				ty = (int) (targetRect.y + targetRect.height);
			} else {
				tx = (int) (targetCX + dx);
				ty = (int) (targetRect.y);
			}
		}
		return new Point(tx, ty);
	}
}
